import traceback
from sqlalchemy.orm import Session
from sqlalchemy.sql import func

from app.common import exceptions as excs
from app.common.enums.resp_enum import ErrTypes
from app.common.enums.bz_enum import SubAccType
from app.models.account import Account, SubAccount, AccountStatement, AccountAdjustDetail
from app.schemas.account import AccountInfo, SubAccountInfo, FullAccountInfo
from app import utils

import logging
logger = logging.getLogger(__name__)

def get_account_info(db: Session, params: dict):
    try:
        merc_no = params.get('merc_no')
        if not merc_no:
            raise excs.GenericException(error_type=ErrTypes.bz_param_validation_error)
        db_acc = db.query(Account).filter(Account.user_name == merc_no).first()
        if db_acc:
            db_sub_accs = db.query(SubAccount).filter(SubAccount.primary_acc_no == db_acc.account_no).all()
            accInfo = AccountInfo(
                **db_acc.__dict__,
                sub_accounts=db_sub_accs
            )
            return accInfo
        else:
            raise excs.GenericException(ErrTypes.db_query_error)
    except excs.GenericException as err:
        logger.error('Error: %s' % err.message)
        raise excs.GenericException(err.error_type)
    except Exception as err:
        logger.exception(err)
        #logger.error(traceback.print_exc)
        raise excs.GenericException(ErrTypes.db_query_error)
    
def get_account(db: Session, user_name: str):
    try:
        if not user_name:
            raise excs.GenericException(error_type=ErrTypes.bz_param_validation_error)
        db_acc = db.query(Account).filter(Account.user_name == user_name).first()
        if db_acc:
            return db_acc
        else:
            raise excs.GenericException(ErrTypes.db_query_error)
    except excs.GenericException as err:
        logger.error('Error: %s' % err.message)
        raise excs.GenericException(err.error_type)
    except Exception as err:
        logger.exception(err)
        #logger.error(traceback.print_exc)
        raise excs.GenericException(ErrTypes.db_query_error)
    
def get_sub_account(db: Session, merc_no: str, sub_type: int):
    try:
        if not merc_no:
            raise excs.GenericException(error_type=ErrTypes.bz_param_validation_error)
        if not sub_type:
            raise excs.GenericException(error_type=ErrTypes.bz_param_validation_error)
        db_acc = db.query(Account).filter(Account.user_name == merc_no).first()
        if db_acc:
            db_sub_acc = db.query(SubAccount).filter(
                SubAccount.primary_acc_no == db_acc.account_no,
                SubAccount.sub_type == sub_type
            ).first()
            return db_sub_acc
        else:
            raise excs.GenericException(ErrTypes.db_query_error)
    except excs.GenericException as err:
        logger.error('Error: %s' % err.message)
        raise excs.GenericException(err.error_type)
    except Exception as err:
        logger.exception(err)
        #logger.error(traceback.print_exc)
        raise excs.GenericException(ErrTypes.db_query_error)

def get_sub_account_info(db: Session, params: dict):
    try:
        merc_no = params.get('merc_no')
        sub_type = params.get('sub_type')
        if not merc_no:
            raise excs.GenericException(error_type=ErrTypes.bz_param_validation_error)
        if not sub_type:
            raise excs.GenericException(error_type=ErrTypes.bz_param_validation_error)
        db_acc = db.query(Account).filter(Account.user_name == merc_no).first()
        if db_acc:
            db_sub_acc = db.query(SubAccount).filter(
                SubAccount.primary_acc_no == db_acc.account_no,
                SubAccount.sub_type == sub_type
            ).first()
            return db_sub_acc
        else:
            raise excs.GenericException(ErrTypes.db_query_error)
    except excs.GenericException as err:
        logger.error('Error: %s' % err.message)
        raise excs.GenericException(err.error_type)
    except Exception as err:
        logger.exception(err)
        #logger.error(traceback.print_exc)
        raise excs.GenericException(ErrTypes.db_query_error)
    
def get_full_account_info(db: Session, params: dict) -> FullAccountInfo:
    try:
        merc_no = params.get('merc_no')
        if not merc_no:
            raise excs.GenericException(error_type=ErrTypes.bz_param_validation_error)
        db_acc = db.query(Account).filter(Account.user_name == merc_no).first()
        if db_acc:
            db_sub_accs = db.query(SubAccount).filter(SubAccount.primary_acc_no == db_acc.account_no).all()
            sub_accs_dt = {}
            for it in db_sub_accs:
                if it.sub_type == SubAccType.BALANCE.value[0]:
                    sub_accs_dt['balance'] = it
                elif it.sub_type == SubAccType.FROZEN.value[0]:
                    sub_accs_dt['frozen'] = it
                elif it.sub_type == SubAccType.PENDING.value[0]:
                    sub_accs_dt['pending'] = it
            sub_acc_info = SubAccountInfo(**sub_accs_dt)
            acc_info = FullAccountInfo(
                account=db_acc,
                sub_acc_info=sub_acc_info
            )
            return acc_info
        else:
            raise excs.GenericException(ErrTypes.db_query_error)
    except excs.GenericException as err:
        logger.error('Error: %s' % err.message)
        raise excs.GenericException(err.error_type)
    except Exception as err:
        logger.exception(err)
        #logger.error(traceback.print_exc)
        raise excs.GenericException(ErrTypes.db_query_error, "查询账户信息出错")

def insert_account_statement(db: Session, params: dict):
    '''deprecated'''
    try:
        if not params.get('account_no'):
            raise excs.GenericException(error_type=ErrTypes.bz_param_validation_error)
        acc_stmt = AccountStatement(
            stmt_id=utils.id_util.gen_trans_id(prefix='TS'),
            account_no=params.get('account_no'),
            sub_account_no=params.get('sub_account_no'),
            sub_type=params.get('sub_type'),
            trans_amount=params.get('trans_amount'),
            trans_fee=params.get('trans_fee'),
            balance=params.get('balance'),
            order_no=params.get('order_no'),
            accounting_type='交易调账'
        )
    except excs.GenericException as err:
        logger.error('Error: %s' % err.message)
        raise excs.GenericException(err.error_type)
    except Exception as err:
        logger.exception(err)
        #logger.error(traceback.print_exc)
        raise excs.GenericException(ErrTypes.db_query_error, "查询账户信息出错")
    

def get_db_account_info(db: Session, merc_no: str) -> tuple:
    try:
        if not merc_no:
            raise excs.GenericException(error_type=ErrTypes.bz_param_validation_error)
        db_acc = db.query(Account).filter(Account.user_name == merc_no).first()
        if db_acc:
            db_sub_accs = db.query(SubAccount).filter(SubAccount.primary_acc_no == db_acc.account_no).all()
            sub_accs_dt = {}
            for it in db_sub_accs:
                if it.sub_type == SubAccType.BALANCE.value[0]:
                    sub_accs_dt['balance'] = it
                elif it.sub_type == SubAccType.FROZEN.value[0]:
                    sub_accs_dt['frozen'] = it
                elif it.sub_type == SubAccType.PENDING.value[0]:
                    sub_accs_dt['pending'] = it
            return db_acc, sub_accs_dt
        else:
            raise excs.GenericException(ErrTypes.db_query_error)
    except excs.GenericException as err:
        logger.error('Error: %s' % err.message)
        raise excs.GenericException(err.error_type)
    except Exception as err:
        logger.exception(err)
        #logger.error(traceback.print_exc)
        raise excs.GenericException(ErrTypes.db_query_error, "查询账户信息出错")

